package com.sh.data.engine.application.service.datadev;

import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson.JSONArray;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.sh.data.engine.application.model.dto.base.PagerResponse;
import com.sh.data.engine.application.model.dto.datadev.*;
import com.sh.data.engine.application.model.mapper.datadev.OfflineDevDirTreeResponseMapper;
import com.sh.data.engine.application.model.mapper.datadev.OfflineDevOperationHistoryResponsePageMapper;
import com.sh.data.engine.application.model.mapper.datadev.OfflineDevSaveNodeCoordParamMapper;
import com.sh.data.engine.application.model.mapper.datadev.OfflineDevTaskFlowVNodeConfigSaveParamMapper;
import com.sh.data.engine.application.model.request.datadev.*;
import com.sh.data.engine.application.model.request.datadev.OfflineDevTaskRunRequest.OfflinedevTaskParamRequest;
import com.sh.data.engine.common.enumDefinition.DSType;
import com.sh.data.engine.common.exception.BusinessException;
import com.sh.data.engine.common.util.ServletUtils;
import com.sh.data.engine.domain.base.model.FileUploadResultDomain;
import com.sh.data.engine.domain.base.model.UserContext;
import com.sh.data.engine.domain.base.service.FileService;
import com.sh.data.engine.domain.dataasset.service.LineageService;
import com.sh.data.engine.domain.datadev.offline.model.domain.*;
import com.sh.data.engine.domain.datadev.offline.model.enums.OfflineDevApiNodeTypeEnum;
import com.sh.data.engine.domain.datadev.offline.model.enums.OfflineDevNodeTypeEnum;
import com.sh.data.engine.domain.datadev.offline.model.enums.OfflineDevTaskStopEnum;
import com.sh.data.engine.domain.datadev.offline.model.param.*;
import com.sh.data.engine.domain.datadev.offline.model.param.OfflineDevTaskRunParam.OfflinedevTaskScriptParamParam;
import com.sh.data.engine.domain.datadev.offline.service.*;
import com.sh.data.engine.domain.integration.datasource.model.domain.DataSourceDomain;
import com.sh.data.engine.domain.integration.datasource.service.DataSourceService;
import com.sh.data.engine.domain.shims.hdfs.util.HdfsUtil;
import com.sh.data.engine.domain.util.ConvertUtil;
import com.sh.data.engine.domain.util.VarParserUtil;
import com.sh.data.engine.infrastructure.config.HDFSConfig;
import com.sh.data.engine.repository.dao.datadev.entity.DatadevMenuNodeEntity;
import com.sh.data.engine.repository.dao.datadev.entity.DatadevScriptEntity;
import com.sh.data.engine.repository.dao.datadev.entity.DatadevSubNodeDependencyEntity;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: mengzheng.mhc
 * @date: 2024/7/10 9:58
 */
@Slf4j
@Service
public class OfflineDevApplicationService {

    @Value("${data.engine.dataDevResource}")
    private String dataDevResource;

    @Autowired
    private OfflineDevMenuNodeService offlineDevMenuNodeService;

    @Autowired
    private LineageService lineageService;

    @Lazy
    @Autowired
    private DatadevMenuNodeService datadevMenuNodeService;

    @Resource
    private DatadevSubNodeService datadevSubNodeService;

    @Resource
    private DatadevSubNodeDependencyService datadevSubNodeDependencyService;

    @Lazy
    @Autowired
    private DatadevScriptService datadevScriptService;

    @Autowired
    private DataSourceService dataSourceService;

    @Autowired
    private DatadevJobService datadevJobService;

    @Autowired
    private HDFSConfig hdfsConfig;

    @Autowired
    private FileService fileService;

    @Autowired
    private OfflineDevDirTreeResponseMapper offlineDevDirTreeResponseMapper;

    @Autowired
    private OfflineDevSaveNodeCoordParamMapper offlineDevSaveNodeCoordParamMapper;

    @Autowired
    private OfflineDevTaskFlowVNodeConfigSaveParamMapper offlineDevTaskFlowVNodeConfigSaveParamMapper;

    @Autowired
    private OfflineDevOperationHistoryResponsePageMapper offlineDevOperationHistoryResponsePageMapper;

    public List<OfflineDevNodeResponse> listAllNodes(Long id) {
        Long projectId = ServletUtils.getProjectId();

        final List<OfflineDevNodeDomain> domainList =
            offlineDevMenuNodeService.getAllNodeByProjectId(id, projectId);

        return ConvertUtil.copyProperties(domainList, OfflineDevNodeResponse.class);
    }

    public List<String> getLineageBySQL(Long nodeId, Long taskFlowId) {
        String dbvendor = "dbvpostgresql";
        boolean treatArgumentsInCountFunctionAsDirectDataflow = true;
        boolean ignoreRecordSet = false;
        boolean ignoreFunction = false;
        boolean showConstantTable = true;
        boolean showTransform = true;
        Set<Long> nodeIds = Sets.newHashSet();
        List<String> res = Lists.newArrayList();
        if (Objects.nonNull(taskFlowId)) {
            List<DatadevSubNodeDependencyEntity> datadevSubNodeDepenDencyList = datadevSubNodeDependencyService.getDatadevSubNodeDepenDencyList(
                taskFlowId);
            for (DatadevSubNodeDependencyEntity dependencyEntity : datadevSubNodeDepenDencyList) {
                nodeIds.add(dependencyEntity.getDownNodeId());
                nodeIds.add(dependencyEntity.getUpNodeId());
            }

            StringBuilder stringBuilder = new StringBuilder();
            for (Long id : nodeIds) {
                DatadevMenuNodeEntity menuNode = datadevMenuNodeService.getById(id);
                Integer nodeType = menuNode.getNodeType();
                if (nodeType.equals(OfflineDevNodeTypeEnum.SQL.getNodeType())) {
                    DatadevScriptEntity datadevScriptByNodeId = datadevScriptService.getDatadevScriptByNodeId(
                        id);
                    String script = datadevScriptByNodeId.getScript();
                    String param = datadevScriptByNodeId.getParam();
                    List<Param> paramList = JSONArray.parseArray(param, Param.class);
                    if (org.apache.commons.collections4.CollectionUtils.isEmpty(paramList)) {
                        paramList = Lists.newArrayList();
                    }
                    final Map<String, String> stringMap =
                        paramList.stream()
                            .collect(Collectors.toMap(x -> x.getParamName(), x -> x.getParamValue()));
                    script = VarParserUtil.process(script, stringMap, null);
                    stringBuilder.append(script);
                    stringBuilder.append("\n");
                }
            }
            try {
                String s = lineageService.generateSqlflowGraph(stringBuilder.toString(), null, null,
                    null, null, true, dbvendor, "fdd",
                    false, false, treatArgumentsInCountFunctionAsDirectDataflow,
                    showConstantTable, showTransform, true, false, ignoreFunction, true, null, null,
                    false,
                    null, false, false, false, false, null, null, null);
                res.add(s);
            } catch (BusinessException e) {
                throw new BusinessException("工作流中存在错误、不完整SQl,请检查");
            }
        } else {
            DatadevScriptEntity datadevScriptByNodeId = datadevScriptService.getDatadevScriptByNodeId(
                nodeId);
            String script = datadevScriptByNodeId.getScript();
            String param = datadevScriptByNodeId.getParam();
            List<Param> paramList = JSONArray.parseArray(param, Param.class);
            if (org.apache.commons.collections4.CollectionUtils.isEmpty(paramList)) {
                paramList = Lists.newArrayList();
            }
            final Map<String, String> stringMap =
                paramList.stream()
                    .collect(Collectors.toMap(x -> x.getParamName(), x -> x.getParamValue()));
            script = VarParserUtil.process(script, stringMap, null);
            try {
                String s = lineageService.generateSqlflowGraph(script, null, null,
                    null, null, true, dbvendor, "fdd",
                    false, false, treatArgumentsInCountFunctionAsDirectDataflow,
                    showConstantTable, showTransform, true, false, ignoreFunction, true, null, null, false,
                    null, false, false, false, false, null, null, null);
                res.add(s);
            } catch (BusinessException e) {
                throw new BusinessException("任务中存在错误、不完整SQL，请检查");
            }
        }
        return res;
    }

    public boolean deleteNode(Long id, Long taskFlowId, Boolean includeChildTask, Boolean physicsDelete) {
        Long projectId = ServletUtils.getProjectId();
        return offlineDevMenuNodeService.deleteNode(id, projectId, includeChildTask, physicsDelete, taskFlowId);
    }

    public boolean restoreNode(Long id) {
        Long projectId = ServletUtils.getProjectId();
        return offlineDevMenuNodeService.restoreNode(id, projectId);
    }

    public boolean editNodeName(Long id, String name) {
        Long projectId = ServletUtils.getProjectId();
        return offlineDevMenuNodeService.editNodeName(id, projectId, name);
    }

    public boolean clearAllNodes() {
        Long projectId = ServletUtils.getProjectId();
        return offlineDevMenuNodeService.clearAllNode(projectId);
    }

    public OfflineDevNodeDetailResponse getTaskDetail(Long id) {
        Long projectId = ServletUtils.getProjectId();
        final OfflineDevNodeDetailDomain taskDetail =
            offlineDevMenuNodeService.getNodeDetail(id, projectId);

        return ConvertUtil.copyProperties(taskDetail, OfflineDevNodeDetailResponse.class);
    }

    public boolean changeDir(OfflineDevDirChangeRequest request) {
        Long projectId = ServletUtils.getProjectId();
        return offlineDevMenuNodeService.changeDir(request.getId(), request.getPid(), projectId);
    }

    public boolean sortDir(OfflineDevDirSortRequest request) {
        Long projectId = ServletUtils.getProjectId();
        return offlineDevMenuNodeService.sortDir(
            request.getId(), request.getSiblingsId(), request.getDropPosition(), projectId);
    }

    public boolean saveDir(OfflineDevDirSaveRequest request) {
        Long projectId = ServletUtils.getProjectId();
        String userId = UserContext.getUserId();

        return offlineDevMenuNodeService.saveDir(
            request.getId(), request.getPid(), request.getName(), projectId, userId);
    }

    public List<OfflineDevDirTreeResponse> getDirTree(Long id) {
        Long projectId = ServletUtils.getProjectId();
        final List<OfflineDevDirTreeDomain> domains = offlineDevMenuNodeService.getDirTree(id, projectId);

        return offlineDevDirTreeResponseMapper.map(domains);
    }

    public List<OfflineDevNodeResponse> getUntilNodeType(Integer nodeType) {
        Long projectId = ServletUtils.getProjectId();
        final List<OfflineDevNodeDomain> domainList =
            offlineDevMenuNodeService.getUntilNodeType(projectId, nodeType);

        return ConvertUtil.copyProperties(domainList, OfflineDevNodeResponse.class);
    }

    public OfflineDevUploadResourceResponse uploadResource(MultipartFile file) throws IOException {
        Long projectId = ServletUtils.getProjectId();
        DataSourceDomain systemDataSourceByProjectId = dataSourceService.getSystemDataSourceByProjectId(
            projectId);
        String dsType = systemDataSourceByProjectId.getDsType();

        // 如果文件不是以.jar结尾
        String fileName = file.getOriginalFilename();
        if (!fileName.toLowerCase().endsWith(".jar")) {
            throw new BusinessException("文件格式错误");
        }

        if (dsType.equalsIgnoreCase(DSType.Hive.name())) {
            OfflineDevUploadResourceResponse offlineDevUploadResourceResponse = new OfflineDevUploadResourceResponse();
            String s = uploadResource(fileName, file.getBytes(), 0, projectId);
            offlineDevUploadResourceResponse.setFilePath(s);
            offlineDevUploadResourceResponse.setOriginalFilename(fileName);
            offlineDevUploadResourceResponse.setFileDownloadUrl(s);
            return offlineDevUploadResourceResponse;
        }
        FileUploadResultDomain upload = null;
        try {
            upload = fileService.upload(file, this.dataDevResource);
        } catch (Exception e) {
            throw new BusinessException("上传文件失败");
        }
        return ConvertUtil.copyProperties(upload, OfflineDevUploadResourceResponse.class);
    }

    public boolean saveResourceTask(OfflineDevTaskResourceSaveRequest request) {
        Long projectId = ServletUtils.getProjectId();
        String userId = UserContext.getUserId();

        OfflineDevTaskResourceSaveParam param =
            ConvertUtil.copyProperties(request, OfflineDevTaskResourceSaveParam.class);
        return offlineDevMenuNodeService.saveResourceTask(param, projectId, userId);
    }

    public List<OfflineDevResourceResponse> listResourceTask(Long nodeId) {
        Long projectId = ServletUtils.getProjectId();
        List<OfflineDevResourceDomain> resourceDomains =
            offlineDevMenuNodeService.listResourceTask(nodeId, projectId);
        return ConvertUtil.copyProperties(resourceDomains, OfflineDevResourceResponse.class);
    }

    public boolean dropResource(Long nodeId, String name) {
        Long projectId = ServletUtils.getProjectId();
        return offlineDevMenuNodeService.dropResourceByIdAndName(nodeId, name, projectId);
    }

    public OfflineDevResourceResponse getResourceDetail(Long nodeId) {
        Long projectId = ServletUtils.getProjectId();
        OfflineDevResourceDomain devResourceDomain =
            offlineDevMenuNodeService.getResourceDetail(nodeId, projectId);
        return ConvertUtil.copyProperties(devResourceDomain, OfflineDevResourceResponse.class);
    }

    public boolean saveTask(OfflineDevTaskSaveRequest request) {
        Long projectId = ServletUtils.getProjectId();
        String userId = UserContext.getUserId();

        if (Objects.equals(OfflineDevNodeTypeEnum.API.getNodeType(), request.getNodeType())) {
            if (!OfflineDevApiNodeTypeEnum.validApiType(request.getApiType())) {
                throw new BusinessException("不支持的接口采集类型");
            }
        }

        OfflineDevTaskSaveParam param =
            ConvertUtil.copyProperties(request, OfflineDevTaskSaveParam.class);

        return offlineDevMenuNodeService.saveTask(param, projectId, userId);
    }

    public boolean setTaskFlowScheduleStatus(Long taskFlowNodeId, Integer status) {
        return offlineDevMenuNodeService.setTaskFlowScheduleStatus(taskFlowNodeId, status);
    }

    public boolean saveWorkTask(OfflineDevTaskSaveRequest request) {
        Long projectId = ServletUtils.getProjectId();
        String userId = UserContext.getUserId();
        request.setNodeType(13);    // sql
        OfflineDevTaskSaveParam param =
            ConvertUtil.copyProperties(request, OfflineDevTaskSaveParam.class);
        return offlineDevMenuNodeService.saveWorkTask(param, projectId, userId);
    }

    public boolean lockTask(Long id, Integer status) {
        Long projectId = ServletUtils.getProjectId();
        String userId = UserContext.getUserId();

        return offlineDevMenuNodeService.lockTask(id, projectId, userId, status);
    }

    public boolean saveTaskScript(OfflineDevTaskScriptSaveRequest request) {
        Long projectId = ServletUtils.getProjectId();
        String userId = UserContext.getUserId();
        return offlineDevMenuNodeService.saveTaskScript(
            request.getId(), projectId, userId, request.getScript(), request.getParams());
    }

    public String importTaskScript(MultipartFile file, Map<String, String[]> parameterMap) {
        Integer nodeType;
        if (null != parameterMap.get("nodeType") && parameterMap.get("nodeType").length > 0) {
            nodeType = Integer.parseInt(parameterMap.get("nodeType")[0]);
        } else {
            throw new BusinessException("nodeType参数必填");
        }

        final OfflineDevNodeTypeEnum nodeTypeEnum = OfflineDevNodeTypeEnum.of(nodeType);

        final String filename = file.getOriginalFilename();

        switch (nodeTypeEnum) {
            case SQL:
                if (!StringUtils.endsWithIgnoreCase(filename, ".sql")
                    && !StringUtils.endsWithIgnoreCase(filename, ".txt")) {
                    throw new BusinessException("必须是.txt或.sql结尾的文件");
                }
                break;
            case SHELL:
                if (!StringUtils.endsWithIgnoreCase(filename, ".sh")
                    && !StringUtils.endsWithIgnoreCase(filename, ".txt")) {
                    throw new BusinessException("必须是.txt或.sh结尾的文件");
                }
                break;
            case PYSPARK:
            case PYTHON2:
            case PYTHON3:
                if (!StringUtils.endsWithIgnoreCase(filename, ".py")
                    && !StringUtils.endsWithIgnoreCase(filename, ".txt")) {
                    throw new BusinessException("必须是.txt或.py结尾的文件");
                }
                break;
        }

        StringBuffer stringBuffer = new StringBuffer("");
        try (BufferedReader reader =
                 new BufferedReader(
                     new InputStreamReader(file.getInputStream(), Charset.forName("utf-8")))) {
            while (true) {
                String line = reader.readLine();
                if (line != null) {
                    stringBuffer.append("\n").append(line);
                } else {
                    break;
                }
            }

            file.getInputStream().close();
        } catch (IOException e) {
            log.error("", e);
        }

        return stringBuffer.toString();
    }

    public OfflineDevTaskScriptDetailResponse getTaskScript(Long id) {
        Long projectId = ServletUtils.getProjectId();
        final OfflineDevTaskScriptDetailDomain taskScript =
            offlineDevMenuNodeService.getTaskScript(id, projectId);

        return ConvertUtil.copyProperties(taskScript, OfflineDevTaskScriptDetailResponse.class);
    }

    public boolean cloneTask(OfflineDevTaskCloneRequest request) {
        Long projectId = ServletUtils.getProjectId();
        String userId = UserContext.getUserId();

        return offlineDevMenuNodeService.cloneTask(
            request.getId(), request.getTaskFlowNodeId(), request.getTaskName(), projectId, userId);
    }

    public PagerResponse<OfflineDevOperationHistoryResponse> getTaskOperationHistory(
        Long nodeId, String content, Integer pageNum, Integer pageSize) {
        Long projectId = ServletUtils.getProjectId();
        var result = offlineDevMenuNodeService.getTaskOperationHistory(nodeId, content, pageNum, pageSize, projectId);
        return offlineDevOperationHistoryResponsePageMapper.toPageResponse(result);
    }

    public OfflineDevTaskTableInfoResponse taskTableList() {
        Long projectId = ServletUtils.getProjectId();
        final OfflineDevTaskTableInfoDomain domain = offlineDevMenuNodeService.taskTableList(projectId);

        return Convert.convert(OfflineDevTaskTableInfoResponse.class, domain);
    }

    public boolean saveTaskFlow(OfflineDevTaskFlowSaveRequest request) {
        Long projectId = ServletUtils.getProjectId();
        String userId = UserContext.getUserId();

        OfflineDevSaveTaskFlowParam param = new OfflineDevSaveTaskFlowParam();
        param.setId(request.getId());
        param.setPid(request.getPid());
        param.setName(request.getName());
        param.setRemark(request.getRemark());
        param.setProjectId(projectId);
        param.setUserId(userId);
        offlineDevMenuNodeService.saveTaskFlow(param);

        return true;
    }

    public OfflineDevTaskFlowDetailResponse getTaskFlowDetail(Long id) {
        Long projectId = ServletUtils.getProjectId();
        OfflineDevTaskFlowDetailDomain taskFlowDetail =
            offlineDevMenuNodeService.getTaskFlowDetail(id, projectId);

        return Convert.convert(OfflineDevTaskFlowDetailResponse.class, taskFlowDetail);
    }

    public OfflineDevTaskFlowDetailResponse.Node saveTaskFlowNode(OfflineDevTaskFlowNodeSaveRequest request) {
        Long projectId = ServletUtils.getProjectId();
        String userId = UserContext.getUserId();

        final OfflineDevTaskFlowNodeSaveParam param =
            ConvertUtil.copyProperties(request, OfflineDevTaskFlowNodeSaveParam.class);

        final OfflineDevTaskFlowDetailDomain.Node node =
            offlineDevMenuNodeService.saveTaskFlowNode(param, projectId, userId);

        return Convert.convert(OfflineDevTaskFlowDetailResponse.Node.class, node);
    }

    public boolean saveTaskFlowNodeRelation(OfflineDevFlowSubTaskDependencySaveRequest request) {
        if (Objects.equals(request.getDownNodeId(), request.getUpNodeId())) {
            throw new BusinessException("不允许有循环依赖");
        }

        Long projectId = ServletUtils.getProjectId();
        String userId = UserContext.getUserId();

        return offlineDevMenuNodeService.saveTaskFlowNodeRelation(
            request.getTaskFlowNodeId(),
            request.getUpNodeId(),
            request.getDownNodeId(),
            request.getStatus(),
            projectId,
            userId);
    }

    public boolean deleteTaskFlowNodeRelation(OfflineDevFlowSubTaskDependencyDeleteRequest request) {
        Long projectId = ServletUtils.getProjectId();
        String userId = UserContext.getUserId();

        return offlineDevMenuNodeService.deleteTaskFlowNodeRelation(
            request.getTaskFlowNodeId(),
            request.getUpNodeId(),
            request.getDownNodeId(),
            projectId,
            userId);
    }

    public OfflineDevTaskFlowVNodeDetailResponse getTaskFlowVNodeDetail(Long nodeId) {
        Long projectId = ServletUtils.getProjectId();
        final OfflineDevTaskFlowVNodeDetailDomain taskFlowVNodeDetail =
            offlineDevMenuNodeService.getTaskFlowVNodeDetail(nodeId, projectId);
        return Convert.convert(OfflineDevTaskFlowVNodeDetailResponse.class, taskFlowVNodeDetail);
    }

    public OfflineDevTaskPropertyResponse getTaskFlowNodeDetail(Long nodeId) {
        Long projectId = ServletUtils.getProjectId();
        final OfflineDevTaskPropertyDomain taskPropertyDomain =
            offlineDevMenuNodeService.getTaskFlowNodeDetail(nodeId, projectId);
        return Convert.convert(OfflineDevTaskPropertyResponse.class, taskPropertyDomain);
    }

    public boolean saveTaskFlowVNodeConfig(Long nodeId, String remark) {
        if (StringUtils.length(remark) > 128) {
            throw new BusinessException("描述长度不能超过128个字符");
        }

        Long projectId = ServletUtils.getProjectId();
        String userId = UserContext.getUserId();

        return offlineDevMenuNodeService.saveTaskFlowVNodeConfig(nodeId, remark, projectId, userId);
    }

    public boolean saveTaskFlowSchedule(OfflineDevTaskFlowVNodeConfigSaveRequest request) {
        Long projectId = ServletUtils.getProjectId();
        String userId = UserContext.getUserId();

        var param = offlineDevTaskFlowVNodeConfigSaveParamMapper.map(request);
        return offlineDevMenuNodeService.saveTaskFlowSchedule(param, projectId, userId);
    }

    public List<OfflineDevResourceListResponse> getOfflineDevResourceList() {
        Long projectId = ServletUtils.getProjectId();
        List<OfflineDevResourceListDomain> domains =
            offlineDevMenuNodeService.getOfflineDevResourceList(projectId);
        return ConvertUtil.copyProperties(domains, OfflineDevResourceListResponse.class);
    }

    public boolean saveFunctionTask(OfflineDevFunctionSaveRequest offlineDevFunctionSaveRequest) {
        Long projectId = ServletUtils.getProjectId();
        String userId = UserContext.getUserId();

        OfflineDevFunctionSaveParam offlineDevFunctionSaveParam =
            ConvertUtil.copyProperties(
                offlineDevFunctionSaveRequest, OfflineDevFunctionSaveParam.class);
        offlineDevFunctionSaveParam.setProjectId(projectId);
        offlineDevFunctionSaveParam.setUserId(userId);
        return offlineDevMenuNodeService.saveFunctionTask(offlineDevFunctionSaveParam);
    }

    public OfflineDevFunctionDetailResponse getOfflineDevFunctionDetail(Long nodeId) {
        OfflineDevFunctionDomain offlineDevFunctionDomain =
            offlineDevMenuNodeService.getOfflineDevFunctionDomain(nodeId);

        return ConvertUtil.copyProperties(
            offlineDevFunctionDomain, OfflineDevFunctionDetailResponse.class);
    }

    public boolean saveTaskFlowNodeConfig(OfflineDevTaskFlowNodeConfigSaveRequest request) {
        Long projectId = ServletUtils.getProjectId();
        String userId = UserContext.getUserId();

        return offlineDevMenuNodeService.saveTaskFlowNodeConfig(
            request.getNodeId(), request.getNodeName(), request.getRemark(), projectId, userId);
    }

    public List<OfflineDevTaskFlowResponse> getTaskFlowList() {
        Long projectId = ServletUtils.getProjectId();
        final List<OfflineDevTaskFlowDomain> taskFlowList =
            offlineDevMenuNodeService.getTaskFlowList(projectId);
        return ConvertUtil.copyProperties(taskFlowList, OfflineDevTaskFlowResponse.class);
    }

    public boolean saveNodeCoord(OfflineDevSaveNodeCoordRequest request) {
        Long projectId = ServletUtils.getProjectId();
        String userId = UserContext.getUserId();

        var param = offlineDevSaveNodeCoordParamMapper.map(request);
        return offlineDevMenuNodeService.saveNodeCoord(param, projectId, userId);
    }

    public boolean stopJob(Long jobId) {
        datadevJobService.stopJob(jobId, OfflineDevTaskStopEnum.TASK_FLOW.getCode());
        return true;
    }

    public OfflineDevTaskLogResponse taskLog(Long jobId, Integer offset, String rsHasShow) {
        OfflineDevTaskLogDomain taskLog = datadevJobService.getTaskLog(jobId, offset, rsHasShow);
        return ConvertUtil.copyProperties(taskLog, OfflineDevTaskLogResponse.class);
    }

    public Long taskStart(OfflineDevTaskRunRequest request) {
        Long projectId = ServletUtils.getProjectId();
        String userId = UserContext.getUserId();
        String script = request.getScript();
        OfflineDevTaskRunParam offlineDevTaskRunParam =
            ConvertUtil.copyProperties(request, OfflineDevTaskRunParam.class);

        List<OfflinedevTaskParamRequest> params = request.getParams();
        List<OfflinedevTaskScriptParamParam> offlinedevTaskScriptParamParams =
            ConvertUtil.copyProperties(params, OfflinedevTaskScriptParamParam.class);
        offlineDevTaskRunParam.setParams(offlinedevTaskScriptParamParams);
        offlineDevTaskRunParam.setProjectId(projectId);
        offlineDevTaskRunParam.setUserId(userId);
        offlineDevTaskRunParam.setScript(script);

        return datadevJobService.startTaskJob(offlineDevTaskRunParam);
    }

    public void downloadTaskResult(Long jobId, String result, HttpServletResponse response) {
        Long projectId = ServletUtils.getProjectId();
        datadevJobService.downloadTaskResult(jobId, result, projectId, response);
    }

    public Long flowTaskStart(Long nodeId) {
        Long projectId = ServletUtils.getProjectId();
        String userId = UserContext.getUserId();

        return datadevJobService.startTaskFlowJob(nodeId, 0, projectId, userId);
    }

    public List<OfflineDevTaskFlowStatusResponse> getTaskFlowStatus(Long jobId) {
        List<OfflineDevTaskFlowStatusDomain> offlineDevTaskFlowStatusDomains =
            datadevJobService.getTaskFlowStatus(jobId);
        return ConvertUtil.copyProperties(
            offlineDevTaskFlowStatusDomains, OfflineDevTaskFlowStatusResponse.class);
    }

    public OfflineDevToolsResponse getDevToolList() {
        Long projectId = ServletUtils.getProjectId();
        OfflineDevToolsDomain r1 = offlineDevMenuNodeService.getDevToolList(projectId);
        return Convert.convert(OfflineDevToolsResponse.class, r1);
    }

    private String uploadResource(String fileName, byte[] data, Integer fileType, Long projectId) {
        String hdfsUrl = hdfsConfig.getHdfsUrl();
        String newFileName = UUID.randomUUID().toString();

        if (fileType.intValue() == 0) {
            newFileName = String.format("%s.jar", newFileName);
        }

        File file = new File(FileUtils.getTempDirectoryPath() + File.separator + newFileName);

        try {
            FileUtils.writeByteArrayToFile(file, data);
        } catch (IOException e) {
            throw new BusinessException("上传失败");
        }

        String username = "hdfs";

        FileSystem hdfs = null;
        String path = null;
        try {

            hdfs =
                HdfsUtil.getFileSystem(
                    null,
                    username,
                    null,
                    hdfsUrl,
                    null,
                    null,
                    null);

            String localDir = file.getAbsolutePath();
            String dir =
                String.format(
                    "%s%s%s%s%s",
                    java.io.File.separator, "jar", java.io.File.separator, projectId, File.separator);

            path = String.format("%s%s", dir, newFileName);

            Path localPath = new Path(new URI(localDir));
            Path hdfsPath = new Path(dir);
            if (hdfs != null) {
                if (!hdfs.exists(hdfsPath)) {
                    hdfs.mkdirs(hdfsPath);
                }
                hdfs.copyFromLocalFile(localPath, hdfsPath);

                hdfs.close();
            }
            boolean delete = file.delete();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new BusinessException("上传失败");
        }

        return path;
    }
}
